package com.mall.b2c.plugin.payment.wft;

import com.mall.b2c.domain.member.MemberDomain;
import com.mall.b2c.domain.order.OrderDomain;
import com.mall.b2c.plugin.payment.AbstractPaymentPlugin;
import com.mall.b2c.plugin.payment.IPaymentEvent;
import com.mall.b2c.plugin.payment.wft.util.MD5;
import com.mall.b2c.plugin.payment.wft.util.SignUtils;
import com.mall.b2c.plugin.payment.wft.util.XmlUtils;
import com.mall.b2c.util.SerialNumberUtil;
import com.mall.b2c.util.SettingUtils;
import com.mall.common.domain.component.ComponentDomain;
import com.mall.common.domain.component.PaymentLogDomain;
import com.mall.common.exception.NoticeException;
import com.mall.common.util.AppContext;
import com.mall.common.util.DateHelper;
import com.mall.common.util.JsonUtil;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.*;

/**
 * 威富通扫描支付插件
 * Created by Misun on 2017/1/19.
 */
public class WftPlugin extends AbstractPaymentPlugin implements IPaymentEvent {

    @Override
    public String onPay(ComponentDomain component, OrderDomain order, String bankInfo, String pickupUrl, String receiveUrl) throws Exception {

        JSONObject jsonObject = null;
        if(component.getIsOfficial() != null && component.getIsOfficial() == Boolean.TRUE){
            jsonObject = component.getConfigJson("payConfig");
        }else{
            jsonObject = component.getConfigJson("testConfig");
        }
        if(jsonObject == null){
            logger.info("系统出错，无法进行支付，配置错误");
            throw new NoticeException("系统出错，无法进行支付");
        }
        SortedMap<String, String> map = new TreeMap<>();
        //交易号
        order.setTradeNo(SerialNumberUtil.buildTradeNo());
        map.put("out_trade_no", order.getTradeNo());
        map.put("body", SettingUtils.get().getName() + "订单");
        map.put("attach","");
        //金额
        if(component.getIsOfficial() == null || component.getIsOfficial() == Boolean.FALSE){
            map.put("total_fee", jsonObject.getString("total_fee"));
        } else {
            map.put("total_fee", String.valueOf(String.valueOf(order.getCash().multiply(BigDecimal.valueOf(100)).longValue())));
        }

        //商户ID
        map.put("mch_id", jsonObject.getString("mch_id"));
        //接口
        JSONObject config = SettingUtils.getDictionaryConfig(bankInfo);
        if (config == null || config.get("service") == null) {
            throw new NoticeException("支付方式配置有误!");
        }
        map.put("service", config.getString("service"));//jsonObject.getString("service")
        map.put("version", jsonObject.getString("version"));
        map.put("charset", jsonObject.getString("charset"));
        map.put("sign_type", jsonObject.getString("sign_type"));
        //异步通知地址
        map.put("notify_url", receiveUrl);
        //IP
        String mch_create_ip = jsonObject.getString("mch_create_ip");
        if(StringUtils.isBlank(mch_create_ip)){
            mch_create_ip = InetAddress.getLocalHost().getHostAddress();
            map.put("mch_create_ip",mch_create_ip);
        }else{
            map.put("mch_create_ip",mch_create_ip);
        }
        map.put("nonce_str", String.valueOf(new Date().getTime()));

        Map<String,String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf, params, false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + jsonObject.getString("key"), "utf-8");
        map.put("sign", sign);

        String reqUrl = jsonObject.getString("req_url");

        logger.info("reqUrl：" + reqUrl);
        logger.info("reqParams:" + XmlUtils.parseXML(map));

        Map<String, String> result = new HashMap<>();

        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        String res = null;
        try {
            HttpPost httpPost = new HttpPost(reqUrl);
            StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map),"utf-8");
            httpPost.setEntity(entityParams);
            httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");
            client = HttpClients.createDefault();
            response = client.execute(httpPost);
            if(response != null && response.getEntity() != null){
                Map<String,String> resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8");
                res = XmlUtils.toXml(resultMap);

                logger.info("请求结果：" + res);

                if(resultMap.containsKey("sign")){
                    if(!SignUtils.checkParam(resultMap, jsonObject.getString("key"))){
                        logger.error("验证签名不通过");
                        throw new NoticeException("系统出错，无法进行支付");
                    }else{
                        if("0".equals(resultMap.get("status")) && "0".equals(resultMap.get("result_code"))){
                            String code_img_url = resultMap.get("code_img_url");
                            logger.info("code_img_url" + code_img_url);
                            result.put("code_img_url", code_img_url);
                            result.put("out_trade_no", map.get("out_trade_no"));
                            result.put("total_fee", map.get("total_fee"));
                            result.put("body", map.get("body"));
                        }else{
                            result.put("err_msg", XmlUtils.toMap(res.getBytes(), "utf-8").get("err_msg"));
                        }
                    }
                }
            }else{
                logger.error("威富通支付请求失败");
                throw new NoticeException("系统出错，无法进行支付");
            }
        } catch (Exception e) {
            logger.error("系统异常", e);
            throw new NoticeException("系统出错，无法进行支付");
        } finally {
            if(response != null){
                response.close();
            }
            if(client != null){
                client.close();
            }
        }
        return JsonUtil.getInstance().obj2json(result);
    }

    @Override
    public String onReturn(Long memberId, Map<String, String> params) throws Exception {
        JSONObject result = new JSONObject();
        ComponentDomain component = componentService.get("componentId", getId());
        JSONObject jsonObject = null;
        if(component.getIsOfficial() != null && component.getIsOfficial() == Boolean.TRUE){
            jsonObject = component.getConfigJson("payConfig");
        }else{
            jsonObject = component.getConfigJson("testConfig");
        }
        if(jsonObject == null){
            result.put("result", "fail");
            logger.error("组件获取失败");
            return result.toString();
        }

        if(params.isEmpty()){
            logger.error("返回参数空了");
            result.put("result", "fail");
            return result.toString();
        }

        String res = XmlUtils.toXml(params);
        logger.info("通知内容：" + res);

        if(params.containsKey("sign")){
            if(!SignUtils.checkParam(params, jsonObject.getString("key"))){
                result.put("result", "fail");
                logger.error("验证签名不通过");
                return result.toString();
            }else{
                String status = params.get("status");
                if(status != null && "0".equals(status)){
                    String result_code = params.get("result_code");
                    if(result_code != null && "0".equals(result_code)) {
                        String out_trade_no = params.get("out_trade_no"); //交易号
                        String transaction_id = params.get("transaction_id"); //威富通交易号
                        List<PaymentLogDomain> logs = paymentLogService.getList("dealId", transaction_id);
                        for (PaymentLogDomain log : logs) {
                            if (out_trade_no.equals(log.getTradeNo())) {
                                if (log.getPaySuccess() == null || !log.getPaySuccess()) {
                                    result.put("isSuccess", false);
                                    result.put("result", "error");
                                    return result.toString();
                                } else {
                                    result.put("isSuccess", true);
                                    result.put("result", "success");
                                    return result.toString();
                                }
                            }
                        }

                        String openid = params.get("openid");
                        String trade_type = params.get("trade_type"); //交易类型
                        String pay_result = params.get("pay_result");
                        String total_fee = params.get("total_fee"); //总金额
                        String fee_type = params.get("fee_type"); //币种
                        String time_end = params.get("time_end"); //完成时间

                        BigDecimal amount = new BigDecimal(0);
                        if (StringUtils.isNotBlank(total_fee)) {
                            amount = new BigDecimal(total_fee).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);
                        }

                        if (memberId == null) {
                            result.put("isSuccess", false);
                            result.put("result", "error");
                            return result.toString();
                        }

                        MemberDomain member = memberService.find(memberId);
                        if (member == null) {
                            result.put("isSuccess", false);
                            result.put("result", "fail");
                            return result.toString();
                        }

                        PaymentLogDomain paymentLog = new PaymentLogDomain();
                        paymentLog.setOrderAccount(amount);
                        paymentLog.setBankId(trade_type);
                        paymentLog.setTradeNo(out_trade_no);
                        paymentLog.setMemberName(member.getUsername());
                        paymentLog.setPayType(component.getPaymemtType());
                        paymentLog.setDealId(transaction_id);
                        paymentLog.setDealTime(DateHelper.string2Date(time_end, "yyyyMMddHHmmss"));
                        paymentLog.setPayAmount(amount);
                        paymentLogService.persist(paymentLog);//保存支付记录

                        if ("0".equals(pay_result)) {//支付成功
                            boolean isSuccess = memberService.recharge(out_trade_no, component.getPaymemtType(), amount, transaction_id, memberId);
                            paymentLog.setPaySuccess(isSuccess);
                            paymentLogService.update(paymentLog);//保存支付记录
                            if (isSuccess && !isRecharge(out_trade_no)) {
                                try {
                                    orderService.pay(out_trade_no, component.getPaymemtType(), transaction_id);
                                    paymentLog.setPaySuccess(true);
                                    paymentLogService.update(paymentLog);//保存支付记录
                                } catch (NoticeException e) {
                                    paymentLog.setPaySuccess(false);
                                    paymentLog.setErrorCode(e.getMessage());
                                    paymentLogService.update(paymentLog);//保存支付记录
                                }
                                result.put("isSuccess", true);
                                result.put("result", "success");
                                return result.toString();
                            }
                            result.put("isSuccess", false);
                            result.put("result", "fail");
                            return result.toString();
                        } else {//支付失败
                            String err_msg = params.get("err_code"); //完成时间
                            paymentLog.setPaySuccess(false);
                            paymentLog.setErrorCode(err_msg);
                            paymentLogService.update(paymentLog);
                            result.put("isSuccess", false);
                            result.put("result", "fail");
                            return result.toString();
                        }
                    }
                }
                result.put("result", "success");
                return result.toString();
            }
        }
        result.put("result", "fail");
        return result.toString();
    }

    @Override
    public String getTradeNo(Map<String, String> params) {
        return params.get("out_trade_no");
    }

    @Override
    public String getType() {
        return "payment";
    }

    @Override
    public String getId() {
        return "b2cWftPlugin";
    }

    @Override
    public String getName() {
        return "威富通支付宝扫描支付";
    }

    @Override
    public String getVersion() {
        return "v1.0.1";
    }

    @Override
    public String getAuthor() {
        return "lzx";
    }

    @Override
    public void perform(Object... params) {

    }

    @Override
    public void register() {

    }
}
